package com.codeoss.framework.workflow.service.impl;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.codeoss.framework.expression.Expression;
import com.codeoss.framework.expression.IScriptServiceStore;
import com.codeoss.framework.util.StringUtils;
import com.codeoss.framework.workflow.context.WorkflowContext;
import com.codeoss.framework.workflow.def.LineDef;
import com.codeoss.framework.workflow.def.TaskNodeDef;
import com.codeoss.module.res.model.ResRole;
import com.codeoss.module.res.model.ResUser;
import com.codeoss.module.res.service.IResRoleService;
import com.codeoss.module.res.service.IResUserService;
import com.codeoss.module.workflow.model.WorkflowTask;
import com.codeoss.module.workflow.service.IWorkflowTaskService;

@Service
public class TaskNodeService extends AbstractNodeService {
	@Autowired
	private IWorkflowTaskService workflowTaskService;
	@Autowired
	private IResUserService resUserService;
	@Autowired
	private IResRoleService resRoleService;
	@Autowired
	private IScriptServiceStore scriptServiceStore;
	
	@Transactional
	public void execute(WorkflowContext workflowContext) {
		TaskNodeDef taskNodeDef = (TaskNodeDef) workflowContext.getNodeDef();
        boolean hasCreateTask=false;
        List<String> taskUserList=new ArrayList<String>();
		String userAssignment = taskNodeDef.getUserAssignment();
		if (!StringUtils.isEmpty(userAssignment)) {
			String userArray[] = userAssignment.split(",");
			for (int i = 0; i < userArray.length; i++) {
				String user=userArray[i].trim();
				if(taskUserList.contains(user)) {
					continue;
				}
				taskUserList.add(user);
				createTask(workflowContext,user);
				hasCreateTask=true;
			}
		}
		
		String roleAssignment=taskNodeDef.getRoleAssignment();
		if (!StringUtils.isEmpty(roleAssignment)) {
			String roleArray[] = roleAssignment.split(",");
			for (int i = 0; i < roleArray.length; i++) {
				String role=roleArray[i].trim();
				QueryWrapper<ResRole> roleQuery=new QueryWrapper<ResRole>();
				roleQuery.eq("code",role);
				ResRole resRole=resRoleService.getOne(roleQuery);
				
				QueryWrapper<ResUser> userQuery=new QueryWrapper<ResUser>();
				userQuery.inSql("id","(select res_user_id from res_rel_user_role where res_role_id="+resRole.getId()+")");
				List<ResUser> userList=resUserService.list(userQuery);
				for (int j = 0; j < userList.size(); j++) {
					if(taskUserList.contains(userList.get(j).getUsername())) {
						continue;
					}
					taskUserList.add(userList.get(j).getUsername());
					createTask(workflowContext,userList.get(j).getUsername());
					hasCreateTask=true;
				}
			}
		}
		
		Expression assignmentExpression=taskNodeDef.getAssignmentExpression();
    	if(assignmentExpression!=null) {
    		Map<String,Object> paraMap=new HashMap<String,Object>();
    		paraMap.put("workflowContext", workflowContext);
    		Object userObject=(Object)scriptServiceStore.getScriptService(assignmentExpression).eval(assignmentExpression.getScript(), paraMap);
    		if(userObject!=null) {
    			if(userObject instanceof String) {
        			String user=(String)userObject;
        			if(!taskUserList.contains(user)) {
        				taskUserList.add(user);
            			createTask(workflowContext,user);
            			hasCreateTask=true;
					}
        		}else {
        			List<String> userList=(List<String>)userObject;
        			for (int i = 0; i < userList.size(); i++) {
        				if(taskUserList.contains(userList.get(i))) {
    						continue;
    					}
    					taskUserList.add(userList.get(i));
        				createTask(workflowContext,userList.get(i));
        				hasCreateTask=true;
    				}
        		}
    			
    		}
    	}
    	if(!hasCreateTask) {
    		throw new RuntimeException("任务节点没有参与者");
    	}
	}

	@Transactional
	public void end(WorkflowContext workflowContext, LineDef lineDef) {
    	TaskNodeDef nodeDef=(TaskNodeDef)workflowContext.getNodeDef();
    	String completeRule=nodeDef.getCompleteRule();
    	
    	QueryWrapper<WorkflowTask> taskQuery=new QueryWrapper<WorkflowTask>();
    	taskQuery.eq("workflow_activity_instance_id", workflowContext.getWorkflowActivityInstance().getId());
    	taskQuery.eq("workflow_token_id", workflowContext.getWorkflowToken().getId());
    	List<WorkflowTask> taskList=workflowTaskService.list(taskQuery);
    	
    	if("all".equals(completeRule)) {
    		boolean isAll=true;
    		for(WorkflowTask workflowTask:taskList) {
    			if(!"CO".equals(workflowTask.getState())) {
    				isAll=false;
    			}
    		}
    		if(isAll) {
    			super.end(workflowContext, lineDef);
    		}
    	}else if ("count".equals(completeRule)) {
    		int ccount=0;
    		for(WorkflowTask workflowTask:taskList) {
    			if("CO".equals(workflowTask.getState())) {
    				ccount++;
    			}
    		}
    		if(nodeDef.getCount()==ccount) {
    			super.end(workflowContext, lineDef);
    		}
		}else if("percent".equals(completeRule)) {
			int ccount=0;
    		for(WorkflowTask workflowTask:taskList) {
    			if("CO".equals(workflowTask.getState())) {
    				ccount++;
    			}
    		}
    		BigDecimal percent=new BigDecimal(ccount).divide(new BigDecimal(taskList.size())).multiply(new BigDecimal(100));
    		if(percent.compareTo(new BigDecimal(nodeDef.getPercent()))>=0) {
    			super.end(workflowContext, lineDef);
    		}
		}	
	}
	
	@Transactional
	protected void createTask(WorkflowContext workflowContext, String actor) {
		WorkflowTask workflowTask = new WorkflowTask();
		workflowTask.setWorkflowActivityInstanceId(workflowContext.getWorkflowActivityInstance().getId());
		workflowTask.setWorkflowTokenId(workflowContext.getWorkflowToken().getId());
		workflowTask.setStartDate(new Timestamp(System.currentTimeMillis()));
		workflowTask.setState("DR");
		workflowTask.setOwner(actor);
		workflowTask.setWorkflowActivityId(workflowContext.getWorkflowActivity().getId());
		workflowTask.setWorkflowProcessId(workflowContext.getWorkflowProcess().getId());
		workflowTask.setWorkflowWorkflowId(workflowContext.getWorkflowProcess().getWorkflowWorkflowId());
		workflowTaskService.insert(workflowTask);
	}
}
